package xyz.apiote.bimba.czwek.settings

import android.content.Context
import android.content.Intent
import android.content.SharedPreferences
import android.graphics.Color
import android.net.ConnectivityManager
import android.os.Bundle
import android.util.Log
import androidx.activity.result.contract.ActivityResultContracts
import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.content.res.AppCompatResources
import androidx.core.content.edit
import androidx.core.widget.addTextChangedListener
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.MainScope
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import org.yaml.snakeyaml.error.YAMLException
import xyz.apiote.bimba.czwek.R
import xyz.apiote.bimba.czwek.api.Bimba
import xyz.apiote.bimba.czwek.api.Server
import xyz.apiote.bimba.czwek.api.TrafficFormatException
import xyz.apiote.bimba.czwek.api.getBimba
import xyz.apiote.bimba.czwek.databinding.ActivityServerChooserBinding
import xyz.apiote.bimba.czwek.settings.feeds.FeedChooserActivity

class ServerChooserActivity : AppCompatActivity() {
	private var _binding: ActivityServerChooserBinding? = null
	private val binding get() = _binding!!

	private val activityLauncher =
		registerForActivityResult(ActivityResultContracts.StartActivityForResult()) {
			if (!preferences.getBoolean("inFeedsTransaction", true)) {
				finish()
			}
		}

	private lateinit var preferences: SharedPreferences

	override fun onCreate(savedInstanceState: Bundle?) {
		super.onCreate(savedInstanceState)
		preferences = getSharedPreferences("shp", MODE_PRIVATE)

		if (intent.getBooleanExtra("simple", false)) {
			setServer("bimba.apiote.xyz", "")
			checkServer(true)
		} else {
			_binding = ActivityServerChooserBinding.inflate(layoutInflater)
			setContentView(binding.root)

			preferences.edit(true) {
				putBoolean("inFeedsTransaction", true)
			}

			if (preferences.getBoolean("shibboleet", false)) {
				binding.button.setBackgroundColor(Color.rgb(35, 93, 121))
				binding.button.setTextColor(Color.WHITE)
			}

			binding.button.isEnabled = false
			binding.serverField.editText!!.addTextChangedListener { editable ->
				binding.button.isEnabled = !editable.isNullOrBlank()
			}

			if (!preferences.getBoolean("firstRun", true)) {
				Server.get(this).let { server ->
					binding.serverField.editText!!.setText(server.host)
					binding.tokenField.editText!!.setText(server.token)
				}
			}

			binding.button.setOnClickListener {
				when (binding.serverField.editText!!.text.toString()) {
					":shibboleet" -> {
						binding.button.setBackgroundColor(Color.rgb(35, 93, 121))
						binding.button.setTextColor(Color.WHITE)
						preferences.edit(true) {
							putBoolean("shibboleet", true)
						}
						if (!preferences.getBoolean("firstRun", true)) {
							Server.get(this).let { server ->
								binding.serverField.editText!!.setText(server.host)
								binding.tokenField.editText!!.setText(server.token)
							}
						}
					}

					";shibboleet" -> {
						_binding = ActivityServerChooserBinding.inflate(layoutInflater)
						setContentView(binding.root)
						preferences.edit(true) {
							putBoolean("shibboleet", false)
						}
						if (!preferences.getBoolean("firstRun", true)) {
							Server.get(this).let { server ->
								binding.serverField.editText!!.setText(server.host)
								binding.tokenField.editText!!.setText(server.token)
							}
						}
					}

					else -> {
						setServer(
							binding.serverField.editText!!.text.toString(),
							binding.tokenField.editText!!.text.toString()
						)
						checkServer(false)
					}
				}
			}
		}
	}

	private fun showDialog(
		title: Int, description: Int, icon: Int, onPositive: (() -> Unit)?
	) {
		MaterialAlertDialogBuilder(this).setIcon(AppCompatResources.getDrawable(this, icon))
			.setTitle(getString(title)).setMessage(getString(description))
			.setNegativeButton(resources.getString(R.string.cancel)) { _, _ -> }.apply {
				if (onPositive != null) {
					setPositiveButton(resources.getString(R.string.cont)) { _, _ ->
						onPositive()
					}
				}
			}.show()
	}

	private fun checkServer(isSimple: Boolean) {
		val cm = getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
		MainScope().launch {
			val result = getBimba(cm, Server.get(this@ServerChooserActivity))
			if (result.error != null) {
				showDialog(R.string.error, result.error.stringResource, result.error.imageResource, null)
				Log.w(
					"ServerChooser", "${result.error.statusCode}, ${getString(result.error.stringResource)}"
				)
				return@launch
			}
			val bimba = try {
				withContext(Dispatchers.IO) {
					Bimba.unmarshal(result.stream!!)
				}
			} catch (e: YAMLException) {
				Log.w("ServerChooser", e.message ?: "YAML error")
				showDialog(R.string.error, R.string.error_traffic_spec, R.drawable.error_server, null)
				return@launch
			} catch (e: TrafficFormatException) {
				Log.w("ServerChooser", e.message)
				showDialog(R.string.error, R.string.error_traffic_spec, R.drawable.error_server, null)
				return@launch
			}

			if (isSimple) {
				updateServer(bimba.servers[0]["url"]!!)
				moveOn(bimba, true)
				return@launch
			}

			if (preferences.getBoolean("shibboleet", false)) {
				val validServers = bimba.servers.filter { !it.getOrDefault("url", null).isNullOrBlank() }
				if (validServers.size > 1) {
					val servers = validServers.toTypedArray()
					MaterialAlertDialogBuilder(this@ServerChooserActivity)
						.setTitle(R.string.choose_server)
						.setItems(servers.map { it["description"] }.toTypedArray()) { _, i ->
							updateServer(servers[i]["url"].toString())
							moveOn(bimba, false)
						}
						.show()
				}
			}
		}
	}

	private fun moveOn(bimba: Bimba, isSimple: Boolean) {
		val token = preferences.getString("token", "")

		if (bimba.isPrivate() && token == "") {
			showDialog(R.string.error, R.string.server_private_question, R.drawable.error_sec, null)
			return
		}
		if (bimba.isRateLimited() && token == "" && !isSimple) {
			showDialog(
				R.string.rate_limit, R.string.server_rate_limited_question, R.drawable.error_limit
			) {
				runFeedsActivity()
			}
			return
		}
		runFeedsActivity()
	}

	private fun setServer(hostname: String, token: String) {
		preferences.edit(true) {
			putString("host", hostname)
			putString("token", token)
		}
	}

	private fun updateServer(apiPath: String) {
		preferences.edit(true) {
			putString("apiPath", apiPath)
		}
	}

	private fun runFeedsActivity() {
		activityLauncher.launch(Intent(this, FeedChooserActivity::class.java))
		if (intent.getBooleanExtra("simple", false)) {
			finish()
		}
	}
}